Docker WordPress - Cách cài đặt WordPress với Docker Compose
Điều này là một trong những lý do khiến WordPress trở thành sự lựa chọn phổ biến khi tạo ra các loại trang web khác nhau, từ blog đến trang sản phẩm đến các trang thương mại điện tử.
Việc chạy WordPress thường liên quan đến việc cài đặt LAMP stack (Linux, Apache, MySQL và PHP) hoặc LEMP (Linux, Nginx, MySQL và PHP), điều này có thể tốn thời gian. Tuy nhiên, bằng cách sử dụng các công cụ như Docker WordPress và Docker WordPress Compose, bạn có thể tối ưu hóa quá trình thiết lập ngăn xếp mong muốn của mình và cài đặt WordPress.
Thay vì cài đặt các thành phần riêng lẻ bằng tay, bạn có thể sử dụng hình ảnh, những thứ chuẩn hóa như thư viện, tệp cấu hình và biến môi trường. Sau đó, chạy những hình ảnh này trong các container, các tiến trình cô lập chạy trên một hệ điều hành chung. Ngoài ra, bằng cách sử dụng Compose, bạn có thể phối hợp nhiều container — ví dụ, một ứng dụng và cơ sở dữ liệu — để giao tiếp với nhau.
Trong hướng dẫn này, bạn sẽ xây dựng cài đặt WordPress đa container. Các container của bạn sẽ bao gồm cơ sở dữ liệu MySQL, máy chủ web Nginx và chính WordPress.
Bạn cũng sẽ bảo vệ cài đặt của mình bằng cách nhận chứng chỉ TLS/SSL từ Let’s Encrypt cho tên miền bạn muốn liên kết với trang web của mình. Cuối cùng, bạn sẽ thiết lập một công việc cron để gia hạn chứng chỉ của mình để đảm bảo tên miền của bạn luôn an toàn.
Yêu cầu đầu tiên
Để thực hiện hướng dẫn này, bạn sẽ cần:
- Một máy chủ chạy Ubuntu 20.04, cùng với một người dùng không phải là root có đặc quyền sudo và tường lửa đang hoạt động.
- Docker WordPress đã được cài đặt trên máy chủ của bạn.
- Docker WordPress Compose đã được cài đặt trên máy chủ.
- Một tên miền đã đăng ký. Hướng dẫn này sẽ sử dụng your_domain trong suốt. Bạn có thể đăng ký tên miền với KDATA.
- Cả hai bản ghi DNS sau được thiết lập cho máy chủ của bạn:
- Một bản ghi A với your_domain trỏ đến địa chỉ IP công cộng của máy chủ của bạn.
- Một bản ghi A với www.your_domain trỏ đến địa chỉ IP công cộng của máy chủ của bạn.
Sau khi bạn đã cài đặt tất cả mọi thứ, bạn sẽ sẵn sàng bắt đầu bước đầu tiên.
Các bước cài đặt Docker WordPress
Bước 1 — Xác định cấu hình Web Server
Trước khi chạy bất kỳ container nào, bước đầu tiên của bạn là xác định cấu hình cho máy chủ web Nginx. Tệp cấu hình của bạn sẽ bao gồm một số khối vị trí (location blocks) cụ thể cho WordPress, cùng với một khối vị trí để chuyển hướng các yêu cầu xác minh của Let’s Encrypt đến ứng dụng Certbot để tự động gia hạn chứng chỉ.
Đầu tiên, tạo một thư mục dự án cho cài đặt Docker WordPress của bạn. Trong ví dụ này, nó được gọi là wordpress. Bạn có thể đặt tên thư mục này khác nếu bạn muốn:
mkdir wordpress
Sau đó, điều hướng đến thư mục:
cd wordpress
Tiếp theo, tạo một thư mục cho tệp cấu hình:
mkdir nginx-conf
Mở tệp cấu hình bằng nano hoặc trình soạn thảo yêu thích của bạn:
nano nginx-conf/nginx.conf
Trong tệp này, thêm một khối máy chủ (server block) với các chỉ thị cho tên máy chủ và thư mục gốc, cùng với các khối vị trí để chuyển hướng yêu cầu xác minh của Certbot, xử lý PHP và yêu cầu tài nguyên tĩnh.
Thêm mã sau vào tệp. Đảm bảo thay thế your_domain bằng tên miền của bạn:
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
index index.php index.html index.htm;
root /var/www/html;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
}
Khối máy chủ của chúng ta bao gồm các thông tin sau:
Chỉ thị (Directives):
-
listen: Điều này bảo Nginx lắng nghe trên cổng 80, cho phép bạn sử dụng plugin webroot của Certbot để yêu cầu chứng chỉ. Lưu ý rằng bạn chưa bao gồm cổng 443 — bạn sẽ cập nhật cấu hình của mình để bao gồm SSL sau khi bạn đã thành công trong việc có được chứng chỉ của mình.
-
server_name: Xác định tên máy chủ và khối máy chủ nào sẽ được sử dụng cho các yêu cầu đến máy chủ của bạn. Hãy đảm bảo thay thế
your_domain
trong dòng này bằng tên miền của bạn. -
index: Chỉ thị này xác định các tệp sẽ được sử dụng làm chỉ mục khi xử lý các yêu cầu đến máy chủ của bạn. Bạn đã sửa đổi thứ tự ưu tiên mặc định ở đây, di chuyển index.php lên trước index.html để Nginx ưu tiên các tệp có tên là index.php khi có thể.
-
root: Chỉ thị này đặt tên thư mục gốc cho các yêu cầu đến máy chủ của bạn. Thư mục này, /var/www/html, được tạo ra như một điểm gắn kết vào thời gian xây dựng bằng các hướng dẫn trong Dockerfile của WordPress. Những hướng dẫn Dockerfile này cũng đảm bảo rằng các tệp từ bản phát hành WordPress được gắn kết vào thư mục này.
Khối vị trí (Location Blocks):
-
location ~ /.well-known/acme-challenge: Khối vị trí này sẽ xử lý các yêu cầu đến thư mục .well-known, nơi Certbot sẽ đặt một tệp tạm thời để xác minh rằng DNS cho tên miền của bạn giải quyết đến máy chủ của bạn. Với cấu hình này, bạn sẽ có thể sử dụng plugin webroot của Certbot để có được chứng chỉ cho tên miền của bạn.
-
location /: Trong khối vị trí này, chỉ thị try_files được sử dụng để kiểm tra các tệp khớp với các yêu cầu URI cụ thể. Thay vì trả lại trạng thái 404 Not Found làm mặc định, bạn sẽ chuyển quyền kiểm soát cho tệp index.php của WordPress với đối số yêu cầu.
-
location ~ .php$: Khối vị trí này sẽ xử lý quá trình xử lý PHP và chuyển tiếp các yêu cầu này đến container wordpress của bạn. Vì hình ảnh Docker WordPress của bạn sẽ được dựa trên hình ảnh php:fpm, bạn cũng sẽ bao gồm các tùy chọn cấu hình cụ thể cho giao thức FastCGI trong khối này.
-
location ~ /.ht: Khối này sẽ xử lý các tệp .htaccess vì Nginx không phục vụ chúng. Chỉ thị deny_all đảm bảo rằng các tệp .htaccess sẽ không bao giờ được phục vụ cho người dùng.
-
location = /favicon.ico, location = /robots.txt: Những khối này đảm bảo rằng các yêu cầu đến /favicon.ico và /robots.txt sẽ không được đăng nhập.
-
location ~ .(css|gif|ico|jpeg|jpg|js|png)$: Khối này tắt chức năng đăng nhập cho các yêu cầu tài nguyên tĩnh và đảm bảo rằng những tài nguyên này có thể được lưu trữ cache mạnh mẽ, vì chúng thường làm tăng chi phí để phục vụ.
Để biết thêm thông tin về việc chuyển tiếp FastCGI, đọc Understanding and Implementing FastCGI Proxying in Nginx. Đối với thông tin về các khối máy chủ và vị trí, kiểm tra Understanding Nginx Server and Location Block Selection Algorithms.
Lưu và đóng tệp khi bạn đã hoàn tất chỉnh sửa. Nếu bạn sử dụng nano, làm điều này bằng cách nhấn CTRL+X, Y, sau đó ENTER. Với cấu hình Nginx của bạn đã có, bạn có thể chuyển sang việc tạo biến môi trường để truyền cho các container ứng dụng và cơ sở dữ liệu của bạn khi chạy.
Bước 2 — Xác định biến môi trường
Các container cơ sở dữ liệu và ứng dụng WordPress của bạn sẽ cần truy cập vào một số biến môi trường cụ thể khi chạy để đảm bảo rằng dữ liệu ứng dụng của bạn tồn tại và có thể truy cập được.
Các biến này bao gồm cả thông tin nhạy cảm và không nhạy cảm: giá trị nhạy cảm cho mật khẩu root của MySQL và người dùng cơ sở dữ liệu ứng dụng, và thông tin không nhạy cảm cho tên cơ sở dữ liệu và máy chủ cơ sở dữ liệu ứng dụng của bạn.
Thay vì đặt tất cả các giá trị này trong tệp Docker WordPress Compose của bạn — tệp chính chứa thông tin về cách các container của bạn sẽ chạy — hãy đặt các giá trị nhạy cảm trong một tệp .env và hạn chế phạm vi lưu trữ của nó. Điều này sẽ ngăn chúng sao chép vào các kho lưu trữ dự án của bạn và bị tiết lộ công khai.
Trong thư mục dự án chính của bạn, ~/wordpress, mở một tệp gọi là .env:
nano .env
Các giá trị mật khẩu bạn đặt trong tệp này bao gồm mật khẩu cho người dùng root của MySQL, và một tên người dùng và mật khẩu mà WordPress sẽ sử dụng để truy cập cơ sở dữ liệu.
Thêm các tên biến và giá trị sau vào tệp. Hãy nhớ cung cấp giá trị của riêng bạn cho mỗi biến:
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password
Đã bao gồm mật khẩu cho tài khoản quản trị root, cũng như tên người dùng và mật khẩu ưa thích của bạn cho cơ sở dữ liệu ứng dụng.
Lưu và đóng tệp khi bạn hoàn tất chỉnh sửa.
Vì tệp .env của bạn chứa thông tin nhạy cảm, bạn muốn đảm bảo rằng nó được bao gồm trong tệp .gitignore và .dockerignore của dự án của bạn. Điều này thông báo cho Git và Docker WordPress những tệp không nên sao chép vào kho lưu trữ Git và hình ảnh Docker WordPress của bạn, tương ứng.
Nếu bạn có ý định làm việc với Git để quản lý phiên bản, khởi tạo thư mục làm việc hiện tại của bạn như là một kho:
git init
Sau đó tạo và mở tệp .gitignore:
nano .gitignore
Thêm .env vào tệp:
.env
Lưu và đóng tệp khi bạn đã hoàn tất chỉnh sửa.
Tương tự, là một biện pháp phòng ngừa tốt, hãy thêm .env vào tệp .dockerignore để nó không xuất hiện trên các container khi bạn sử dụng thư mục này làm ngữ cảnh xây dựng.
Mở tệp:
nano .dockerignore
Thêm .env vào tệp:
.env
Dưới đây, bạn có thể tùy chọn thêm các tệp và thư mục liên quan đến quá trình phát triển ứng dụng của bạn:
.env
.git
docker-compose.yml
.dockerignore
Lưu và đóng tệp khi bạn đã hoàn tất.
Với thông tin nhạy cảm của bạn đã có, bạn có thể chuyển sang định nghĩa các dịch vụ của mình trong tệp docker-compose.yml.
Bước 3 — Xác định dịch vụ với Docker WordPress Compose
Tệp docker-compose.yml của bạn sẽ chứa các định nghĩa dịch vụ cho cài đặt của bạn. Một dịch vụ trong Docker WordPress Compose là một container đang chạy, và các định nghĩa dịch vụ chỉ định thông tin về cách mỗi container sẽ chạy.
Sử dụng Docker WordPress Compose, bạn có thể xác định các dịch vụ khác nhau để chạy ứng dụng đa container vì Compose cho phép bạn liên kết các dịch vụ này với nhau thông qua mạng và thư mục chia sẻ.
Điều này sẽ hữu ích cho cài đặt hiện tại của bạn vì bạn sẽ tạo ra các container khác nhau cho cơ sở dữ liệu, ứng dụng WordPress và máy chủ web. Bạn cũng sẽ tạo ra một container để chạy ứng dụng Certbot để lấy chứng chỉ cho máy chủ web của bạn.
Để bắt đầu, tạo và mở tệp docker-compose.yml:
nano docker-compose.yml
Thêm mã sau để xác định phiên bản của tệp Compose và dịch vụ cơ sở dữ liệu db:
version: '3'
services:
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
volumes:
- dbdata:/var/lib/mysql
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
Định nghĩa dịch vụ db chứa các tùy chọn sau:
-
image: Điều này thông báo cho Docker WordPress Compose sử dụng hình ảnh nào để tạo container. Bạn đang sử dụng hình ảnh mysql:8.0 ở đây để tránh xung đột trong tương lai khi hình ảnh mysql:latest tiếp tục được cập nhật. Đối với thông tin chi tiết về việc ghim phiên bản và tránh xung đột phụ thuộc, đọc tài liệu Docker WordPress về các thực hành tốt nhất với Dockerfile.
-
container_name: Điều này chỉ định một tên cho container.
-
restart: Điều này xác định chính sách khởi động lại container. Mặc định là no, nhưng bạn đã đặt container để khởi động lại trừ khi nó bị dừng bằng cách thủ công.
-
env_file: Tùy chọn này thông báo cho Compose rằng bạn muốn thêm biến môi trường từ một tệp có tên .env, nằm trong ngữ cảnh xây dựng của bạn. Trong trường hợp này, ngữ cảnh xây dựng là thư mục làm việc hiện tại của bạn.
-
environment: Tùy chọn này cho phép bạn thêm các biến môi trường bổ sung, vượt ra ngoài những cái được xác định trong tệp .env của bạn. Bạn sẽ đặt biến MYSQL_DATABASE bằng wordpress để cung cấp một tên cho cơ sở dữ liệu ứng dụng của bạn. Vì đây là thông tin không nhạy cảm, bạn có thể bao gồm nó trực tiếp trong tệp docker-compose.yml.
-
volumes: Ở đây, bạn đang gắn kết một volume có tên là dbdata vào thư mục /var/lib/mysql trên container. Đây là thư mục dữ liệu tiêu chuẩn cho MySQL trên hầu hết các bản phân phối.
-
command: Tùy chọn này chỉ định một lệnh để ghi đè lệnh CMD mặc định cho hình ảnh. Trong trường hợp cụ thể này, bạn sẽ thêm một tùy chọn vào lệnh mysqld tiêu chuẩn của hình ảnh Docker WordPress, khởi động máy chủ MySQL trên container. Tùy chọn này, --default-authentication-plugin=mysql_native_password, đặt biến hệ thống --default-authentication-plugin thành mysql_native_password, chỉ định cơ chế xác thực nào sẽ quản lý các yêu cầu xác thực mới đối với máy chủ. Vì PHP và do đó hình ảnh WordPress của bạn không hỗ trợ cách xác thực mặc định mới của MySQL, bạn phải thực hiện điều này để xác thực người dùng cơ sở dữ liệu ứng dụng của bạn.
-
networks: Điều này xác định rằng dịch vụ ứng dụng của bạn sẽ tham gia vào mạng app-network, mà bạn sẽ định nghĩa ở cuối tệp.
Tiếp theo, phía dưới định nghĩa dịch vụ ứng dụng wordpress của bạn:
...
wordpress:
depends_on:
- db
image: wordpress:5.1.1-fpm-alpine
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
networks:
- app-network
Trong định nghĩa dịch vụ này, bạn đặt tên cho container và xác định một chính sách khởi động lại, như bạn đã làm với dịch vụ db. Bạn cũng thêm một số tùy chọn cụ thể cho container này:
-
depends_on: Tùy chọn này đảm bảo rằng các container của bạn sẽ bắt đầu theo thứ tự phụ thuộc, với container wordpress bắt đầu sau container db. Ứng dụng WordPress của bạn phụ thuộc vào sự tồn tại của cơ sở dữ liệu và người dùng ứng dụng của bạn, vì vậy việc diễn đạt sự phụ thuộc này sẽ giúp ứng dụng của bạn bắt đầu đúng cách.
-
image: Đối với cài đặt này, bạn đang sử dụng hình ảnh WordPress 5.1.1-fpm-alpine. Như đã thảo luận ở Bước 1, việc sử dụng hình ảnh này đảm bảo rằng ứng dụng của bạn sẽ có bộ xử lý php-fpm mà Nginx yêu cầu để xử lý PHP. Đây cũng là một hình ảnh alpine, xuất phát từ dự án Alpine Linux, giúp giữ cho kích thước tổng thể của hình ảnh của bạn giảm xuống. Đối với thông tin chi tiết về ưu và nhược điểm của việc sử dụng hình ảnh alpine và liệu điều này có phù hợp với ứng dụng của bạn hay không, hãy xem thảo luận đầy đủ trong phần Image Variants trên trang hình ảnh Docker Hub WordPress.
-
env_file: Một lần nữa, bạn chỉ định rằng bạn muốn lấy các giá trị từ tệp .env của mình, vì đây là nơi bạn đã định nghĩa người dùng và mật khẩu cơ sở dữ liệu ứng dụng của bạn.
-
environment: Ở đây, bạn sử dụng các giá trị bạn đã xác định trong tệp .env của mình, nhưng gán chúng cho các tên biến mà hình ảnh WordPress mong đợi: WORDPRESS_DB_USER và WORDPRESS_DB_PASSWORD. Bạn cũng đang xác định một WORDPRESS_DB_HOST, sẽ là máy chủ MySQL đang chạy trên container db có thể truy cập được qua cổng mặc định của MySQL, là 3306. WORDPRESS_DB_NAME của bạn sẽ là giá trị giống như bạn đã chỉ định trong định nghĩa dịch vụ MySQL cho MYSQL_DATABASE của bạn: wordpress.
-
volumes: Bạn đang gắn kết một volume có tên là wordpress vào điểm gắn kết /var/www/html được tạo ra bởi hình ảnh WordPress. Sử dụng một volume có tên như vậy sẽ cho phép bạn chia sẻ mã ứng dụng của bạn với các container khác.
-
networks: Bạn cũng thêm container wordpress vào mạng app-network.
Tiếp theo, phía dưới định nghĩa dịch vụ Nginx webserver của bạn:
...
webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
Ở đây, bạn đặt tên cho container và làm cho nó phụ thuộc vào container wordpress về thứ tự bắt đầu. Bạn cũng đang sử dụng một hình ảnh alpine — hình ảnh Nginx 1.15.12-alpine.
Định nghĩa dịch vụ này cũng bao gồm các tùy chọn sau:
-
ports: Điều này mở cổng 80 để kích hoạt các tùy chọn cấu hình bạn đã xác định trong tệp nginx.conf của mình ở Bước 1.
-
volumes: Ở đây, bạn đang xác định một kết hợp giữa các volumes có tên và bind mounts:
wordpress:/var/www/html:
Điều này sẽ gắn kết mã ứng dụng WordPress của bạn vào thư mục /var/www/html, thư mục bạn đã đặt làm root trong khối máy chủ Nginx của bạn../nginx-conf:/etc/nginx/conf.d:
Điều này sẽ bind mount thư mục cấu hình Nginx trên máy chủ vào thư mục tương ứng trên container, đảm bảo rằng mọi thay đổi bạn thực hiện vào các tệp trên máy chủ sẽ được phản ánh trong container.certbot-etc:/etc/letsencrypt:
Điều này sẽ gắn kết các chứng chỉ và khóa Let’s Encrypt tương ứng cho tên miền của bạn vào thư mục thích hợp trên container.
Bạn cũng đã thêm container này vào mạng app-network.
Cuối cùng, phía dưới định nghĩa dịch vụ cuối cùng của bạn cho dịch vụ certbot. Hãy chắc chắn thay thế địa chỉ email và tên miền được liệt kê ở đây bằng thông tin của bạn:
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain
Định nghĩa này bảo cho Compose lấy hình ảnh certbot/certbot từ Docker Hub. Nó cũng sử dụng volumes có tên để chia sẻ tài nguyên với container Nginx, bao gồm chứng chỉ tên miền và khóa trong certbot-etc và mã ứng dụng trong wordpress.
Một lần nữa, bạn đã sử dụng depends_on để chỉ định rằng container certbot nên được bắt đầu sau khi dịch vụ máy chủ web đang chạy.
Bạn cũng đã bao gồm một tùy chọn command chỉ định một lệnh con để chạy với lệnh mặc định certbot của container. Lệnh con certonly sẽ lấy một chứng chỉ với các tùy chọn sau:
-
--webroot: Điều này báo cho Certbot sử dụng plugin webroot để đặt các tệp trong thư mục webroot để xác thực. Plugin này phụ thuộc vào phương thức xác thực HTTP-01, sử dụng một yêu cầu HTTP để chứng minh rằng Certbot có thể truy cập tài nguyên từ một máy chủ phản hồi theo một tên miền cụ thể.
-
--webroot-path: Điều này chỉ định đường dẫn của thư mục webroot.
-
--email: Địa chỉ email mà bạn chọn để đăng ký và phục hồi.
-
--agree-tos: Điều này chỉ định rằng bạn đồng ý với hợp đồng đăng ký ACME.
-
--no-eff-email: Điều này thông báo cho Certbot rằng bạn không muốn chia sẻ email của mình với Electronic Frontier Foundation (EFF). Hãy thay loại bỏ nếu bạn muốn.
-
--staging: Điều này thông báo cho Certbot rằng bạn muốn sử dụng môi trường thử nghiệm của Let’s Encrypt để lấy chứng chỉ thử nghiệm. Sử dụng tùy chọn này cho phép bạn kiểm tra các tùy chọn cấu hình của mình và tránh các hạn chế yêu cầu tên miền có thể xảy ra. Đối với thông tin chi tiết về những hạn chế này, vui lòng đọc tài liệu về các hạn chế của Let’s Encrypt.
-
-d: Điều này cho phép bạn chỉ định tên miền mà bạn muốn áp dụng cho yêu cầu của mình. Trong trường hợp này, bạn đã bao gồm your_domain và www.your_domain. Hãy chắc chắn thay thế chúng bằng tên miền của bạn.
Dưới định nghĩa dịch vụ certbot, thêm định nghĩa mạng và volumes của bạn:
...
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
Khóa volumes ở cấp độ cao nhất của bạn xác định các volumes certbot-etc, wordpress, và dbdata. Khi Docker tạo volumes, nội dung của volume được lưu trữ trong một thư mục trên hệ thống tệp hệ thống máy chủ /var/lib/docker/volumes/, được quản lý bởi Docker. Nội dung của mỗi volume sau đó được gắn kết từ thư mục này đến bất kỳ container nào sử dụng volume đó. Như vậy, bạn có thể chia sẻ mã và dữ liệu giữa các container.
Mạng bridge do người dùng định nghĩa app-network cho phép giao tiếp giữa các container của bạn vì chúng nằm trên cùng một máy chủ daemon Docker. Điều này tối ưu hóa giao tiếp và luồng thông tin trong ứng dụng, vì nó mở tất cả các cổng giữa các container trên cùng một mạng bridge mà không tiếp xúc bất kỳ cổng nào với thế giới bên ngoài.
Do đó, các container db, wordpress và webserver có thể giao tiếp với nhau, và bạn chỉ cần mở cổng 80 để truy cập giao diện trước của ứng dụng.
Dưới đây là nội dung của tệp docker-compose.yml toàn bộ:
version: '3'
services:
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
volumes:
- dbdata:/var/lib/mysql
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
wordpress:
depends_on:
- db
image: wordpress:5.1.1-fpm-alpine
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
networks:
- app-network
webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
Lưu và đóng tệp khi bạn đã hoàn tất chỉnh sửa.
Với định nghĩa dịch vụ của bạn đã được thiết lập, bạn đã sẵn sàng khởi động các container và kiểm tra yêu cầu chứng chỉ của mình.
Bước 4 — Lấy chứng chỉ SSL và thông tin đăng nhập
Bắt đầu các container của bạn với lệnh docker-compose up, nó sẽ tạo và chạy các container của bạn theo thứ tự bạn đã chỉ định. Bằng cách thêm cờ -d, lệnh sẽ chạy các container db, wordpress và webserver ở nền:
docker-compose up -d
Kết quả đầu ra sau đây xác nhận rằng các dịch vụ của bạn đã được tạo:
Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot ... done
Sử dụng docker-compose ps để kiểm tra trạng thái của các dịch vụ của bạn:
docker-compose ps
Khi hoàn thành, các dịch vụ db, wordpress và webserver của bạn sẽ ở trạng thái Up và container certbot sẽ thoát với thông báo trạng thái 0:
Name Command State Ports
-------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
wordpress docker-entrypoint.sh php-fpm Up 9000/tcp
Bất kỳ trạng thái khác ngoài Up trong cột State cho các dịch vụ db, wordpress, hoặc webserver, hoặc một trạng thái thoát khác 0 cho container certbot đều có nghĩa là bạn có thể cần kiểm tra nhật ký dịch vụ với lệnh docker-compose logs:
docker-compose logs service_name
Bạn có thể kiểm tra xem chứng chỉ của bạn đã được gắn kết vào container webserver với docker-compose exec:
docker-compose exec webserver ls -la /etc/letsencrypt/live
Khi yêu cầu chứng chỉ của bạn thành công, đây là đầu ra:
total 16
drwx------ 3 root root 4096 May 10 15:45 .
drwxr-xr-x 9 root root 4096 May 10 15:45 ..
-rw-r--r-- 1 root root 740 May 10 15:45 README
drwxr-xr-x 2 root root 4096 May 10 15:45 your_domain
Bây giờ bạn đã biết yêu cầu của mình sẽ thành công, bạn có thể chỉnh sửa định nghĩa dịch vụ certbot để loại bỏ cờ --staging.
Mở file docker-compose.yml:
nano docker-compose.yml
Tìm phần trong tệp chứa định nghĩa dịch vụ certbot và thay thế cờ --staging trong tùy chọn command bằng cờ --force-renewal, điều này sẽ cho biết Certbot rằng bạn muốn yêu cầu một chứng chỉ mới với các tên miền giống như một chứng chỉ hiện tại. Dưới đây là định nghĩa dịch vụ certbot với cờ được cập nhật:
certbot:
image: certbot/certbot
container_name: certbot_app
restart: unless-stopped
command: certonly --webroot --webroot-path=/var/www/html --email your_email@example.com --agree-tos --no-eff-email --force-renewal -d your_domain
volumes:
- wp_data:/var/www/html
networks:
- app-network
depends_on:
- wordpress
Bạn có thể chạy docker-compose up
để tạo lại container certbot. Bạn cũng sẽ bao gồm tùy chọn --no-deps
để thông báo cho Compose rằng nó có thể bỏ qua việc khởi động dịch vụ webserver, vì nó đã đang chạy:
docker-compose up --force-recreate --no-deps certbot
Đầu ra sau đây cho thấy rằng yêu cầu chứng chỉ của bạn đã thành công:
Recreating certbot ... done
Attaching to certbot
certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log
certbot | Plugins selected: Authenticator webroot, Installer None
certbot | Renewing an existing certificate
certbot | Performing the following challenges:
certbot | http-01 challenge for your_domain
certbot | http-01 challenge for www.your_domain
certbot | Using the webroot path /var/www/html for all unmatched domains.
certbot | Waiting for verification...
certbot | Cleaning up challenges
certbot | IMPORTANT NOTES:
certbot | - Congratulations! Your certificate and chain have been saved at:
certbot | /etc/letsencrypt/live/your_domain/fullchain.pem
certbot | Your key file has been saved at:
certbot | /etc/letsencrypt/live/your_domain/privkey.pem
certbot | Your cert will expire on 2019-08-08. To obtain a new or tweaked
certbot | version of this certificate in the future, simply run certbot
certbot | again. To non-interactively renew *all* of your certificates, run
certbot | "certbot renew"
certbot | - Your account credentials have been saved in your Certbot
certbot | configuration directory at /etc/letsencrypt. You should make a
certbot | secure backup of this folder now. This configuration directory will
certbot | also contain certificates and private keys obtained by Certbot so
certbot | making regular backups of this folder is ideal.
certbot | - If you like Certbot, please consider supporting our work by:
certbot |
certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
certbot | Donating to EFF: https://eff.org/donate-le
certbot exited with code 0
Với chứng chỉ của bạn đã sẵn có, bạn có thể tiếp tục sửa đổi cấu hình Nginx để bao gồm SSL.
Bước 5 — Sửa đổi cấu hình và định nghĩa dịch vụ của Web Server
Kích hoạt SSL trong cấu hình Nginx của bạn sẽ bao gồm thêm một chuyển hướng HTTP sang HTTPS, chỉ định vị trí chứng chỉ và khóa SSL của bạn, và thêm các tham số và tiêu đề bảo mật.
Vì bạn sẽ tạo lại dịch vụ webserver để bao gồm những thêm vào này, bạn có thể dừng nó ngay bây giờ:
docker-compose stop webserver
Trước khi sửa đổi tệp cấu hình, hãy lấy tham số bảo mật Nginx được đề xuất từ Certbot bằng cách sử dụng curl:
curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
Lệnh này sẽ lưu các tham số này vào một tệp có tên options-ssl-nginx.conf, nằm trong thư mục nginx-conf.
Tiếp theo, xóa tệp cấu hình Nginx mà bạn đã tạo trước đó:
rm nginx-conf/nginx.conf
Tạo và mở một phiên bản khác của tệp:
nano nginx-conf/nginx.conf
Thêm mã sau đây vào tệp để chuyển hướng HTTP sang HTTPS và thêm chứng chỉ SSL, giao thức và tiêu đề bảo mật. Nhớ thay thế your_domain bằng tên miền của bạn:
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your_domain www.your_domain;
index index.php index.html index.htm;
root /var/www/html;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
include /etc/nginx/conf.d/options-ssl-nginx.conf;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# enable strict transport security only if you understand the implications
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
}
Khối máy chủ HTTP chỉ định thư mục gốc cho các yêu cầu gia hạn của Certbot đến thư mục .well-known/acme-challenge. Nó cũng bao gồm một chỉ thị rewrite chuyển hướng các yêu cầu HTTP đến thư mục gốc đến HTTPS.
Khối máy chủ HTTPS kích hoạt ssl và http2. Để biết thêm về cách HTTP/2 phát triển từ các giao thức HTTP và những lợi ích nó mang lại cho hiệu suất trang web, vui lòng đọc giới thiệu về Cách Cài Đặt Nginx với Hỗ Trợ HTTP/2 trên Ubuntu 18.04.
Khối này cũng bao gồm địa chỉ và khóa SSL của bạn, cùng với các tham số bảo mật Certbot được khuyến nghị mà bạn đã lưu vào nginx-conf/options-ssl-nginx.conf.
Ngoài ra, có một số tiêu đề bảo mật được bao gồm để giúp bạn đạt được điểm A trên các trang kiểm tra máy chủ như SSL Labs và Security Headers. Các tiêu đề này bao gồm X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy, và X-XSS-Protection. Tiêu đề Strict Transport Security (HSTS) đã được chú thích — hãy kích hoạt nó chỉ khi bạn hiểu rõ về các ảnh hưởng và đã đánh giá chức năng "preload" của nó.
Các chỉ thị root và index cũng được đặt trong khối này, cũng như các khối vị trí cụ thể cho WordPress đã được thảo luận trong Bước 1.
Sau khi bạn đã hoàn tất việc chỉnh sửa, hãy lưu và đóng tệp.
Trước khi tái tạo dịch vụ webserver, bạn sẽ cần thêm một ánh xạ cổng 443 vào định nghĩa dịch vụ webserver của bạn.
Mở tệp docker-compose.yml của bạn:
nano docker-compose.yml
Trong định nghĩa dịch vụ webserver, thêm ánh xạ cổng sau:
...
webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
Dưới đây là toàn bộ tệp docker-compose.yml sau khi chỉnh sửa:
version: '3'
services:
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
volumes:
- dbdata:/var/lib/mysql
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
wordpress:
depends_on:
- db
image: wordpress:5.1.1-fpm-alpine
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
networks:
- app-network
webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
Lưu và đóng tệp khi bạn đã chỉnh sửa xong.
Tạo lại dịch vụ webserver:
docker-compose up -d --force-recreate --no-deps webserver
Kiểm tra các dịch vụ của bạn bằng:
docker-compose ps
Kết quả nên cho thấy rằng các dịch vụ db, wordpress và webserver của bạn đang chạy:
Output
Name Command State Ports
----------------------------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
wordpress docker-entrypoint.sh php-fpm Up 9000/tcp
Với các container đang chạy, bạn có thể hoàn tất việc cài đặt WordPress thông qua giao diện web.
Bước 6 — Hoàn tất cài đặt qua giao diện web
Với các container đang chạy, hoàn tất cài đặt thông qua giao diện web của WordPress.
Trong trình duyệt web của bạn, truy cập vào tên miền của máy chủ của bạn. Hãy nhớ thay thế your_domain bằng tên miền riêng của bạn:
https://your_domain
Chọn ngôn ngữ bạn muốn sử dụng:
Sau khi nhấp vào Tiếp tục, bạn sẽ đến trang thiết lập chính, nơi bạn cần chọn một tên cho trang web của bạn và một tên người dùng. Đây là ý tưởng tốt để chọn một tên người dùng dễ nhớ ở đây (thay vì "admin") và một mật khẩu mạnh. Bạn có thể sử dụng mật khẩu mà WordPress tạo tự động hoặc tạo một mật khẩu riêng của bạn.
Cuối cùng, bạn sẽ cần nhập địa chỉ email của bạn và quyết định liệu bạn có muốn ngăn chặn các công cụ tìm kiếm đánh dấu trang web của bạn hay không:
Nhấp vào install WordPress ở cuối trang sẽ chuyển bạn đến một ô đăng nhập:
Sau khi đăng nhập, bạn sẽ có quyền truy cập vào bảng điều khiển quản trị WordPress:
Với việc cài đặt WordPress của bạn hoàn tất, bạn có thể thực hiện các bước để đảm bảo rằng chứng chỉ SSL của bạn sẽ được gia hạn tự động.
Bước 7 — Gia hạn chứng chỉ chứng chỉ
Let's Encrypt có hiệu lực trong 90 ngày. Bạn có thể thiết lập quá trình gia hạn tự động để đảm bảo chúng không hết hạn. Một cách để làm điều này là tạo một công việc với tiện ích lập lịch cron. Trong ví dụ sau, bạn sẽ tạo một công việc cron để định kỳ chạy một tập lệnh sẽ gia hạn chứng chỉ và tải lại cấu hình Nginx của bạn.
Trước tiên, mở tập lệnh được gọi là ssl_renew.sh:
nano ssl_renew.sh
Thêm đoạn mã sau vào tập lệnh để gia hạn chứng chỉ và tải lại cấu hình máy chủ web của bạn. Hãy nhớ thay thế tên người dùng ví dụ ở đây bằng tên người dùng không phải root của bạn:
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/sammy/wordpress/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Tập lệnh này đầu tiên gán binary docker-compose vào một biến được gọi là COMPOSE, và chỉ định tùy chọn --no-ansi, sẽ chạy các lệnh docker-compose mà không có ký tự điều khiển ANSI. Sau đó, nó thực hiện điều tương tự với binary docker. Cuối cùng, nó chuyển đến thư mục dự án ~/wordpress và chạy các lệnh docker-compose sau:
- docker-compose run: Điều này sẽ bắt đầu một container certbot và ghi đè lên lệnh được cung cấp trong định nghĩa dịch vụ certbot của bạn. Thay vì sử dụng lệnh con certonly, nó sử dụng lệnh con renew, sẽ gia hạn chứng chỉ gần hết hạn. Cũng bao gồm tùy chọn --dry-run để kiểm tra tập lệnh của bạn.
- docker-compose kill: Điều này sẽ gửi một tín hiệu SIGHUP đến container webserver để tải lại cấu hình Nginx. Sau đó, nó chạy docker system prune để loại bỏ tất cả các container và hình ảnh không sử dụng.
Đóng tệp khi bạn đã chỉnh sửa xong. Làm cho nó có thể thực thi bằng lệnh sau:
chmod +x ssl_renew.sh
Tiếp theo, mở tệp crontab gốc của bạn để chạy tập lệnh gia hạn tại một khoảng thời gian cụ thể:
sudo crontab -e
Nếu đây là lần đầu bạn chỉnh sửa tệp này, bạn sẽ được yêu cầu chọn một trình soạn thảo:
Output
no crontab for root - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/nano <---- easiest
2. /usr/bin/vim.basic
3. /usr/bin/vim.tiny
4. /bin/ed
Choose 1-4 [1]:
...
Ở cuối tệp này, thêm dòng sau:
...
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
Điều này sẽ đặt khoảng thời gian cho công việc là mỗi năm lần, để bạn có thể kiểm tra xem yêu cầu gia hạn của mình có hoạt động như mong đợi hay không. Một tệp nhật ký, cron.log, được tạo để ghi lại đầu ra có liên quan từ công việc.
Sau năm phút, kiểm tra cron.log để xác nhận xem yêu cầu gia hạn đã thành công hay không:
tail -f /var/log/cron.log
Đầu ra sau đây xác nhận một gia hạn thành công:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/your_domain/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Nhấn CTRL+C trong cửa sổ terminal để thoát.
Bạn có thể sửa đổi tệp crontab để đặt khoảng thời gian hàng ngày. Để chạy tập lệnh mỗi ngày vào lúc trưa, ví dụ, bạn sẽ sửa đổi dòng cuối cùng của tệp như sau:
...
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
Bạn cũng sẽ muốn loại bỏ tùy chọn --dry-run khỏi tập lệnh ssl_renew.sh của bạn:
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/sammy/wordpress/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Công việc cron của bạn sẽ đảm bảo rằng chứng chỉ Let’s Encrypt của bạn không hết hạn bằng cách gia hạn chúng khi chúng đủ điều kiện. Bạn cũng có thể thiết lập quay vòng nhật ký với tiện ích Logrotate để quay vòng và nén các tệp nhật ký của bạn.
Trong hướng dẫn về Docker WordPress, bạn đã sử dụng Docker Compose để tạo một cài đặt WordPress với máy chủ web Nginx. Như một phần của quy trình làm việc này, bạn đã nhận được chứng chỉ TLS/SSL cho tên miền bạn muốn liên kết với trang web WordPress của mình. Ngoài ra, bạn đã tạo một công việc cron để gia hạn các chứng chỉ này khi cần thiết.
Mọi người cùng tìm kiếm: wordpress docker, wordpress docker compose, docker wordpress